<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | 短信发送
// +----------------------------------------------------------------------
namespace app\sso\http\api;

use app\sso\lib\sms\Tencent;
use app\sso\model\UserModel;
use Inphp\Core\Attributes\Method;
use Inphp\Core\Db\Db;
use Inphp\Core\Modules;
use Inphp\Core\Object\Message;
use Inphp\Core\Util\Str;

class sms
{
    /**
     * 短信发送
     * @return Message
     */
    #[Method(Method::POST)] public function index(): Message
    {
        //国家代码
        $countryCode = POST("countryCode", 86);
        if (stripos($countryCode, "+") === 0) {
            $countryCode = substr($countryCode, 1);
        }
        //默认使用中国号码
        $countryCode = is_numeric($countryCode) && $countryCode >= 0 ? $countryCode : 86;
        //配置
        $configAll = Modules::getModule("sso")->getConfig();
        $config = is_array($configAll) ? $configAll["sms"] : [];
        //检测
        $countryList = $config["countryList"] ?? [];
        $countryCodeList = [];
        foreach ($countryList as $cl) {
            $code = stripos($cl["code"], "+") === 0 ? substr($cl["code"], 1) : $cl["code"];
            $countryCodeList[] = $code;
        }
        $countryCodeList = !empty($countryCodeList) ? $countryCodeList : [86];
        if (!in_array($countryCode, $countryCodeList)) {
            return httpMessage("国家代码无效");
        }
        //手机号码
        $phone = POST("phone");
        if (!Str::isPhoneNumber($phone, $countryCode)) {
            return httpMessage("手机号码格式错误");
        }
        //是否有验证码，强制使用
        $vCode = POST("vCode");
        $vCode = !empty($vCode) ? Str::trim($vCode) : null;
        if (empty($vCode)) {
            return httpMessage(10);
        }
        $vCodeId = POST("vCodeId");
        $vCodeId = !empty($vCodeId) ? Str::trim($vCodeId) : 0;
        if (!matchVCode($vCode, $vCodeId)) {
            return httpMessage(11);
        }
        //使用类型，默认为通用
        $action = POST("action");
        $action = !empty($action) ? $action : \app\sso\lib\sms\SMS::ACT_ALL;
        //对一些情况进行特别处理
        if ($action == \app\sso\lib\sms\SMS::ACT_AUTH && !($configAll["auth"]["smsAutoRegister"] ?? false)) {
            //账号授权，需要查询该手机号码是否在账号里边
            $user = UserModel::emptyQuery()
                ->where("countryCode", $countryCode)
                ->where("phone", $phone)
                ->first();
            if (empty($user)) {
                return httpMessage('该手机号码不存在系统中，同时当前禁止新手机注册，无法发送短信验证码！');
            }
        }
        //查询发送次数，同一号码，1小时内，最多发X条短信
        $oneHourLimit = $config["oneHourLimit"] ?? 0;
        $oneHourLimit = is_numeric($oneHourLimit) && $oneHourLimit > 0 ? ceil($oneHourLimit) : 0;
        if ($oneHourLimit > 0) {
            //仅在大于0的情况去判断
            $rows = Db::from("sso_sms")
                ->where("phone", $phone)
                ->where("countryCode", $countryCode)
                ->where("time", ">=", date("Y-m-d H:i:s", time() - 3600))
                ->rows();
            if ($rows >= $oneHourLimit) {
                return httpMessage(23);
            }
        }
        //可以发送，如果是debug，需要直接返回验证码
        $lifeTime = $config["lifeTime"] ?? 600;
        $lifeTime = is_numeric($lifeTime) && $lifeTime > 300 ? ceil($lifeTime) : 600;
        $sms = [
            "phone"         => $phone,
            "countryCode"   => $countryCode,
            "code"          => Str::randomNumber(6),
            "action"        => $action,
            "expireTime"    => date("Y-m-d H:i:s", time() + $lifeTime),
            "send"          => 2,
            "state"         => 2,
            "ip"            => getIP()
        ];
        $db = Db::from("sso_sms");
        if ($db->insert($sms)) {
            //ID
            $id = $db->getLastInsertId();
            //发送成功，将旧短信全失效
            @Db::from("sso_sms")
                ->where("countryCode", $countryCode)
                ->where("phone", $phone)
                ->where("action", $action)
                ->where("id", "!=", $id)
                ->where("state", 2)
                ->update(["state" => 0]);
            //如果开启debug，直接返回验证码
            $debug = $config["debug"] ?? false;
            if ($debug) {
                return httpMessage(0, "success", [
                    "code"  => $sms["code"]
                ]);
            }
            //发送
            if ($countryCode !== 86) {
                $international = $config["international"] ?? $config;
                $apiName = $international["apiName"] ?? Tencent::class;
            } else {
                $apiName = $config["apiName"] ?? Tencent::class;
            }
            $apiName = class_exists($apiName) ? $apiName : Tencent::class;
            $success = call_user_func_array([$apiName, "sendVerifyCode"], [$countryCode, $phone, $sms["code"]]);
            //修改发送状态
            @Db::from("sso_sms")->where("id", $id)->update(["send" => $success ? 1 : 0]);
            return httpMessage($success ? 0 : 22, $success ? "发送成功" : "短信发送失败", [
                "code"  => ""
            ]);
        }
        return httpMessage("短信保存失败");
    }

    /**
     * 获取国家代码列表
     * @return array[]
     */
    public function countryList(): array
    {
        //配置
        $config = Modules::getModule("sso")->getConfig("sms");
        $config = is_array($config) ? $config : [];
        //检测
        return $config["countryList"] ?? [["code" => 86, "en" => "China", "cn" => "中国大陆"]];
    }
}